﻿using Infrastructure;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.IdentityModel.Tokens;
using NUnit.Framework;
using Microsoft.EntityFrameworkCore;

namespace OpenAuth.App.Report
{
    /// <summary>
    /// 巡检轮班到位率
    /// </summary>
    public class InspectPlanShiftReport : BaseApp<InspectPlan>
    {
        private IAuth _auth;
        public InspectPlanShiftReport(IUnitWork unitWork, IRepository<InspectPlan> repository, RevelanceManagerApp app, IAuth auth) : base(unitWork, repository)
        {
            _auth = auth;
        }

        public List<InspectPlanReportResp> LoadData(InspectPlanReportReq req)
        {
            var loginContext = _auth.GetCurrentUser();
            if (loginContext == null)
            {
                throw new CommonException("登录已过期", Define.INVALID_TOKEN);
            }

            req.StartTime = req.StartTime?.ToString("yyyy-MM-dd HH:mm:ss").ToDateTime() ??
                            DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd 00:00:00").ToDateTime();
            req.EndTime = req.EndTime?.ToString("yyyy-MM-dd HH:mm:ss").ToDateTime() ??
                          DateTime.Now.ToString("yyyy-MM-dd 00:00:00").ToDateTime();
            req.EndTime = req.EndTime?.AddMilliseconds(1);



            Expression<Func<InspectItem, bool>> teamExpression = PredicateBuilder.True<InspectItem>();
            Expression<Func<InspectSchedule, bool>> expression = PredicateBuilder.True<InspectSchedule>();
            expression = expression.And(u => u.StartTime >= req.StartTime && u.EndTime < req.EndTime && u.ShiftTeam != "");
            if (!string.IsNullOrEmpty(req.PlanId))
                expression = expression.And(u => u.InspectPlanId == req.PlanId);
            if (!string.IsNullOrEmpty(req.Team))
            {
                expression = expression.And(u => u.ShiftTeam == req.Team);
                teamExpression = teamExpression.And(u => u.Id == req.Team);
            }

            List<InspectSchedule> schedules = UnitWork.Find(expression).ToList();
            var scheduleIdList = schedules.Select(s => s.Id).ToList();
            var teamIds = schedules.Select(u => u.ShiftTeam).Distinct();
            teamExpression = teamExpression.And(u => teamIds.Contains(u.Id));
            List<InspectItem> teams = UnitWork.Find(teamExpression).ToList();

            DateTime flagTime = req.EndTime.Value.AddDays(5);
            var violationList = UnitWork.Find<InspectViolation>(u => u.CreateTime >= req.StartTime && u.CreateTime < flagTime).ToList();
            var list0 = violationList.Where(u => u.Category == 0).Select(u => u.InspectScheduleId);
            var list1 = violationList.Where(u => u.Category == 1).Select(u => u.InspectScheduleId);
            var list2 = violationList.Where(u => u.Category == 2).Select(u => u.InspectScheduleId);
            List<InspectPlanReportResp> result = new List<InspectPlanReportResp>();
            foreach (var team in teams)
            {
                var allScheduleList = schedules.Where(u => u.ShiftTeam == team.Id);
                var all = allScheduleList.Count();
                var done = allScheduleList.Count(u => u.IsInspection && !list2.Contains(u.Id));
                //var yxClass = schedules.Where(u => u.ShiftTeam == team.Id && u.IsInspection && !list2.Contains(u.Id));
                //var done = yxClass.Count();
                //var overTimeCount = list1.Intersect(yxClass.Select(u => u.Id)).Count();
                //todo 超时可优化
                var resp = new InspectPlanReportResp()
                {
                    ShiftTeam = team.Name,
                    ShiftTeamId = team.Id,
                    All = all,
                    Done = done,
                    NotInspect = allScheduleList.Count(u => list0.Contains(u.Id)),
                    Leak = allScheduleList.Count(u => list2.Contains(u.Id)),
                    OverTime = allScheduleList.Count(u => list1.Contains(u.Id)),
                    Percentage = all == 0 ? 0 : Math.Round((Convert.ToDecimal(done) / all * 100), 1)
                };
                result.Add(resp);
            }
            result.OrderByDescending(u => u.Percentage);

            return result;
        }

        public TableData GetReportDetailList(InspectPlanReportReq req)
        {
            var loginContext = _auth.GetCurrentUser();
            if (loginContext == null)
            {
                throw new CommonException("登录已过期", Define.INVALID_TOKEN);
            }
            //默认查昨天一天
            req.StartTime = req.StartTime?.ToString("yyyy-MM-dd HH:mm:ss").ToDateTime() ??
                            DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd 00:00:00").ToDateTime();
            req.EndTime = req.EndTime?.ToString("yyyy-MM-dd HH:mm:ss").ToDateTime() ??
                          DateTime.Now.ToString("yyyy-MM-dd 00:00:00").ToDateTime();
            req.EndTime = req.EndTime?.AddMilliseconds(1);
            List<string> orgIdList = new List<string>();
            if (!string.IsNullOrWhiteSpace(req.OrgId))
            {
                var org = loginContext.Orgs.SingleOrDefault(u => u.Id == req.OrgId);
                foreach (Org item in loginContext.Orgs)
                {
                    if (item.CascadeId.Contains(org.CascadeId))
                    {
                        orgIdList.Add(item.Id);
                    }
                }
            }
            else
            {
                orgIdList = loginContext.Orgs.Select(u => u.Id).ToList();
            }

            Expression<Func<InspectViolation, bool>> violationExpression = PredicateBuilder.True<InspectViolation>();
            violationExpression = violationExpression.And(u => orgIdList.Contains(u.OrgId))
                .And(u => u.CreateTime >= req.StartTime).And(u => u.CreateTime < req.EndTime).And(u=>u.Category==req.Category);

            var scheduleIdList = UnitWork.Find<InspectSchedule>(u => u.EndTime >= req.StartTime
            && u.StartTime <= req.EndTime && u.ShiftTeam == req.Team).Select(u=>u.Id).ToList();
            var result = new TableData();
            var dataList = new List<InspectViolationList>();
            var violationList = UnitWork.Find(violationExpression);
            var data = violationList.Include(u => u.InspectPlan)
                .Include(u => u.Org).Include(u => u.InspectSchedule)
                .OrderByDescending(u => u.CreateTime).ToList();
            data = data.Where(u => scheduleIdList.Contains(u.InspectScheduleId)).ToList();
            var userList = UnitWork.Find<User>(null).ToList();
            foreach (var item in data)
            {
                var obj = new InspectViolationList
                {
                    Id = item.Id,
                    PlanName = item.InspectPlan?.Name,
                    OrgName = item.Org.Name,
                    Reason = item.Reason,
                    AuditMind = item.AuditMind,
                    IsViolation = item.IsViolation,
                    Status = item.Status,
                    Category = item.Category
                };
                if (item.InspectSchedule != null)
                {
                    string className;
                    if (string.IsNullOrEmpty(item.InspectSchedule.ShiftTeam))
                    {
                        className = item.InspectSchedule.ClassName;
                    }
                    else
                    {
                        var startTime = item.InspectSchedule.StartTime;
                        var endTime = item.InspectSchedule.EndTime;
                        className = startTime.ToShortDateString() == endTime.ToShortDateString()
                            ? $"{item.InspectSchedule.ClassName}({startTime:yyyy-MM-dd HH:mm}至{endTime:HH:mm})"
                            : $"{item.InspectSchedule.ClassName}({startTime:yyyy-MM-dd HH:mm}至{endTime:yyyy-MM-dd HH:mm})";
                    }
                    obj.ClassName = className;
                    string userNames;
                    if (string.IsNullOrEmpty(item.InspectSchedule.ShiftTeam))
                    {
                        string[] ids = item.InspectSchedule.Executor.Split("，");
                        var users = userList.Where(u => ids.Contains(u.Id)).Select(u => u.Name);
                        userNames = string.Join(",", users);
                    }
                    else
                    {
                        var users = userList.Where(u => u.InspectTeam == item.InspectSchedule.ShiftTeam).Select(u => u.Name);
                        userNames = string.Join(",", users);
                    }
                    obj.Person = userNames;
                }

                dataList.Add(obj);
            }
            result.data = dataList;
            result.count = violationList.Count();
            return result;
        }
    }
}
